#ifndef NYUVALUE_HPP_
#define NYUVALUE_HPP_

class NyuContext;

typedef long NyuValue;
typedef long NyuInt;
typedef float NyuFloat;
typedef NyuValue (*NyuFunc)(NyuContext* c);

#define NYU_INT_TO_VALUE(X) ((X) << 2)
#define NYU_FUNC_TO_VALUE(X) ((NyuValue)(X) | 1)
#define NYU_OBJECT_TO_VALUE(X) ((NyuValue)(X) | 2)
#define NYU_BLOCK_TO_VALUE(X) ((NyuValue)(X) | 3)
#define NYU_VALUE_TO_INT(X) ((X) >> 2)
#define NYU_VALUE_TO_POINTER(X) ((X) & ~3)

#define NYU_VALUE_UNTAG_NATIVE(X) ((NyuFunc)((X) ^ 1))
#define NYU_VALUE_UNTAG_OBJECT(X) ((NyuObject*)((X) ^ 2))
#define NYU_VALUE_UNTAG_BLOCK(X) ((NyuTreeList*)((X) ^ 3))

#define NYU_VALUE_IS_OBJECT(X) (NYU_VALUE_TAG(X) == NYU_VALUE_TAG_OBJECT)
#define NYU_VALUE_IS_NATIVE_OR_BLOCK(X) ((X) & 1)

#define NYU_VALUE_CLEAR_TAG(X) ((X) & ~3)

enum NyuValueTag {
    NYU_VALUE_TAG_INT,
    NYU_VALUE_TAG_NATIVE,
    NYU_VALUE_TAG_OBJECT,
    NYU_VALUE_TAG_BLOCK,
};

enum NyuValueTag2 {
    NYU_VALUE_TAG_INT_INT,
    NYU_VALUE_TAG_INT_NATIVE,
    NYU_VALUE_TAG_INT_OBJECT,
    NYU_VALUE_TAG_INT_BLOCK,
    NYU_VALUE_TAG_NATIVE_INT,
    NYU_VALUE_TAG_NATIVE_NATIVE,
    NYU_VALUE_TAG_NATIVE_OBJECT,
    NYU_VALUE_TAG_NATIVE_BLOCK,
    NYU_VALUE_TAG_OBJECT_INT,
    NYU_VALUE_TAG_OBJECT_NATIVE,
    NYU_VALUE_TAG_OBJECT_OBJECT,
    NYU_VALUE_TAG_OBJECT_BLOCK,
    NYU_VALUE_TAG_BLOCK_INT,
    NYU_VALUE_TAG_BLOCK_NATIVE,
    NYU_VALUE_TAG_BLOCK_OBJECT,
    NYU_VALUE_TAG_BLOCK_BLOCK,
};

#define NYU_VALUE_TAG(X) ((NyuValueTag)((X) & 3))
#define NYU_VALUE_TAG2(X,Y) ((NyuValueTag2)((((X) & 3) << 2) | ((Y) & 3)))

#define NYU_MAXARGS 64
#define NYU_SCOPE_CACHE_SIZE 128

#endif /* NYUVALUE_HPP_ */
